package com.ruyuan.user.server.controller;

import com.ruyuan.common.model.Features;
import com.ruyuan.common.model.PageDTO;
import com.ruyuan.common.web.model.WebResponse;
import com.ruyuan.gateway.sdk.facade.RuyuanGatewayFacade;
import com.ruyuan.gateway.sdk.model.ApiAuthorizationRequireInfo;
import com.ruyuan.user.api.model.constants.UserAccountInfoExtendKeys;
import com.ruyuan.user.api.model.enums.AuthResourceTypeEnum;
import com.ruyuan.user.server.controller.converter.WebAuthorityConverter;
import com.ruyuan.user.server.controller.request.DelAuthResourceRequest;
import com.ruyuan.user.server.controller.request.SaveFunctionResourceRequest;
import com.ruyuan.user.server.controller.request.SaveUserRequest;
import com.ruyuan.user.server.controller.response.DataResourceVO;
import com.ruyuan.user.server.controller.response.FunctionResourceTreeVO;
import com.ruyuan.user.server.domain.model.AuthResource;
import com.ruyuan.user.server.domain.model.AuthResourceFeaturesKey;
import com.ruyuan.user.server.domain.model.User;
import com.ruyuan.user.server.domain.service.AuthorityDomainService;
import com.ruyuan.user.server.domain.service.request.PageQueryAuthResourceReq;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.*;

import static com.ruyuan.user.api.model.enums.AuthResourceTypeEnum.*;

/**
 * @author xx
 */
@Controller
@RequestMapping("/api/user/authority")
public class AuthorityController {

    @Autowired
    private WebAuthorityConverter converter;

    @Autowired
    private AuthorityDomainService authorityDomainService;

    @Autowired
    private RuyuanGatewayFacade ruyuanGatewayFacade;

    @RequestMapping("/saveFunctionResource")
    @ResponseBody
    public WebResponse<Long> saveFunctionResource(@Validated @RequestBody SaveFunctionResourceRequest request, BindingResult bindingResult) {
        if (bindingResult.hasErrors()) {
            return WebResponse.failWithMsg(bindingResult.getFieldError().getDefaultMessage());
        }
        AuthResource authResource = converter.convertSaveFunctionResourceRequestToModel(request);
        Long res = authorityDomainService.saveAuthResource(authResource);
        reportApiAuthorityRequirement(Long.valueOf(ruyuanGatewayFacade.getCurrentUser().getExtendInfo().get(UserAccountInfoExtendKeys.ROOT_ORG_ID)));
        return WebResponse.successWithData(res);
    }
    
    private void reportApiAuthorityRequirement(Long orgId) {
        // 构建上报接口权限列表
        PageQueryAuthResourceReq req = new PageQueryAuthResourceReq();
        req.setOrgId(orgId);
        req.setAuthResourceTypes(Arrays.asList(API));
        req.setCurrent(1);
        req.setPageSize(Integer.MAX_VALUE);
        PageDTO<AuthResource> pageDTO = authorityDomainService.queryAuthResourceByCondition(req);
        List<ApiAuthorizationRequireInfo> infoList = new ArrayList<>();
        // 不需要登录的接口优先级放在最前面
        ApiAuthorizationRequireInfo loginInfo = new ApiAuthorizationRequireInfo();
        loginInfo.setPath("/api/user/doLogin");
        loginInfo.setNeedLogin(false);
        loginInfo.setPriority(-1);
        infoList.add(loginInfo);
        // 处理业务接口
        if (CollectionUtils.isNotEmpty(pageDTO.getData())) {
            for (int i = 0; i < pageDTO.getData().size(); i++) {
                AuthResource authResource = pageDTO.getData().get(i);
                ApiAuthorizationRequireInfo info = new ApiAuthorizationRequireInfo();
                Features features = Optional.ofNullable(authResource.getFeatures()).orElse(Features.of());
                info.setPath(features.getFeature(AuthResourceFeaturesKey.URL));
                info.setNeedLogin(true);
                info.setPriority(i);
                info.setRequiredAuthorityCode(authResource.getRelatedAuthorities().get(0).getCode());
                infoList.add(info);
            }
        }
        // 最后是api登陆态校验
        ApiAuthorizationRequireInfo finalInfo = new ApiAuthorizationRequireInfo();
        finalInfo.setPath("/api/**");
        finalInfo.setNeedLogin(true);
        finalInfo.setPriority(Integer.MAX_VALUE);
        infoList.add(finalInfo);
        ruyuanGatewayFacade.reportApiAuthorityRequirement(infoList);
    }

    @GetMapping("/queryFunctionTree")
    @ResponseBody
    public WebResponse<List<FunctionResourceTreeVO>> queryFunctionTree() {
        Long orgId = Long.valueOf(ruyuanGatewayFacade.getCurrentUser().getExtendInfo().get(UserAccountInfoExtendKeys.ROOT_ORG_ID));
        PageQueryAuthResourceReq req = new PageQueryAuthResourceReq();
        req.setOrgId(orgId);
        req.setAuthResourceTypes(Arrays.asList(AuthResourceTypeEnum.MENU, AuthResourceTypeEnum.OPERATION));
        req.setCurrent(1);
        req.setPageSize(Integer.MAX_VALUE);
        PageDTO<AuthResource> pageDTO = authorityDomainService.queryAuthResourceByCondition(req);
        List<AuthResource> authResources = pageDTO.getData();
        if (CollectionUtils.isEmpty(authResources)) {
            return WebResponse.successWithData(new ArrayList<>());
        }
        return WebResponse.successWithData(converter.convertModelToTreeVO(authResources));
    }

    @PostMapping("/delFunctionResource")
    @ResponseBody
    public WebResponse<Boolean> delFunctionResource(@Validated @RequestBody DelAuthResourceRequest request, BindingResult bindingResult) {
        if (bindingResult.hasErrors()) {
            return WebResponse.failWithMsg(bindingResult.getFieldError().getDefaultMessage());
        }
        //不允许删除有子节点的资源
        Long orgId = Long.valueOf(ruyuanGatewayFacade.getCurrentUser().getExtendInfo().get(UserAccountInfoExtendKeys.ROOT_ORG_ID));
        PageQueryAuthResourceReq pageQueryAuthResourceRequest = new PageQueryAuthResourceReq();
        pageQueryAuthResourceRequest.setOrgId(orgId);
        // 查菜单和操作两种资源
        pageQueryAuthResourceRequest.setAuthResourceTypes(Arrays.asList(MENU, OPERATION));
        pageQueryAuthResourceRequest.setCurrent(1);
        pageQueryAuthResourceRequest.setPageSize(Integer.MAX_VALUE);
        PageDTO<AuthResource> authResourcePageDTO = authorityDomainService.queryAuthResourceByCondition(pageQueryAuthResourceRequest);
        List<AuthResource> authResources = authResourcePageDTO.getData();
        AuthResource delResource = authResources.stream().filter(authResource -> authResource.getId().equals(request.getResourceId())).findFirst().orElse(null);
        if (delResource == null) {
            return WebResponse.failWithMsg("resource not exist");
        }
        Map<String, List<AuthResource>> authResourceParentCodeMap = converter.groupByParentCode(authResources);
        List<AuthResource> children = authResourceParentCodeMap.get(delResource.getCode());
        if (CollectionUtils.isNotEmpty(children)) {
            return WebResponse.failWithMsg("resource have children, can not delete");
        }

        authorityDomainService.delAuthResource(request.getResourceId());
        reportApiAuthorityRequirement(orgId);
        return WebResponse.successWithData(true);
    }

    @GetMapping("/queryDataResource")
    @ResponseBody
    public WebResponse<List<DataResourceVO>> queryDataResource() {
        Long orgId = Long.valueOf(ruyuanGatewayFacade.getCurrentUser().getExtendInfo().get(UserAccountInfoExtendKeys.ROOT_ORG_ID));
        PageQueryAuthResourceReq pageQueryAuthResourceRequest = new PageQueryAuthResourceReq();
        pageQueryAuthResourceRequest.setOrgId(orgId);
        // 查菜单和操作两种资源
        pageQueryAuthResourceRequest.setAuthResourceTypes(Arrays.asList(DATA));
        pageQueryAuthResourceRequest.setCurrent(1);
        pageQueryAuthResourceRequest.setPageSize(Integer.MAX_VALUE);
        PageDTO<AuthResource> authResourcePageDTO = authorityDomainService.queryAuthResourceByCondition(pageQueryAuthResourceRequest);
        if (authResourcePageDTO == null || CollectionUtils.isEmpty(authResourcePageDTO.getData())) {
            return WebResponse.successWithData(new ArrayList<>());
        }
        return WebResponse.successWithData(converter.convertModelToDataResourceVO(authResourcePageDTO.getData()));
    }

}
